<html lang="zh-CN"><head><meta charset="UTF-8"><style>.nodata  main {width:1000px;margin: auto;}</style></head><body class="nodata " style=""><div class="main_father clearfix d-flex justify-content-center " style="height:100%;"> <div class="container clearfix " id="mainBox"><main><div class="blog-content-box">
<div class="article-header-box">
<div class="article-header">
<div class="article-title-box">
<h1 class="title-article" id="articleContentId">(A卷,200分)- 去除多余空格（Java & JS & Python）</h1>
</div>
</div>
</div>
<div id="blogHuaweiyunAdvert"></div>

        <div id="article_content" class="article_content clearfix">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-044f2cf1dc.css">
                <div id="content_views" class="htmledit_views">
                    <h4 id="main-toc">题目描述</h4> 
<p>去除文本多余空格&#xff0c;但不去除配对单引号之间的多余空格。给出关键词的起始和结束下标&#xff0c;去除多余空格后刷新关键词的起始和结束下标。</p> 
<p>条件约束&#xff1a;<br /> 1&#xff0c;不考虑关键词起始和结束位置为空格的场景&#xff1b;<br /> 2&#xff0c;单词的的开始和结束下标保证涵盖一个完整的单词&#xff0c;即一个坐标对开始和结束下标之间不会有多余的空格&#xff1b;<br /> 3&#xff0c;如果有单引号&#xff0c;则用例保证单引号成对出现&#xff1b;<br /> 4&#xff0c;关键词可能会重复&#xff1b;<br /> 5&#xff0c;文本字符长度length取值范围&#xff1a;[0, 100000];</p> 
<p></p> 
<h4 id="%E8%BE%93%E5%85%A5%E6%8F%8F%E8%BF%B0">输入描述</h4> 
<p>输入为两行字符串&#xff1a;</p> 
<p>第一行&#xff1a;待去除多余空格的文本&#xff0c;用例保证如果有单引号&#xff0c;则单引号成对出现&#xff0c;且单引号可能有多对。</p> 
<p>第二行&#xff1a;关键词的开始和结束坐标&#xff0c;关键词间以逗号区分&#xff0c;关键词内的开始和结束位置以单空格区分。</p> 
<p></p> 
<h4 id="%E8%BE%93%E5%87%BA%E6%8F%8F%E8%BF%B0">输出描述</h4> 
<p>输出为两行字符串&#xff1a;</p> 
<p>第一行&#xff1a;去除多余空格后的文本<br /> 第二行&#xff1a;去除多余空格后的关键词的坐标开始和结束位置&#xff0c;为数组方式输出。</p> 
<p></p> 
<h4 id="%E7%94%A8%E4%BE%8B">用例</h4> 
<table border="1" cellpadding="1" cellspacing="1" style="width:500px;"><tbody><tr><td style="width:86px;">输入</td><td style="width:412px;">Life is painting a  picture, not doing &#39;a  sum&#39;.<br /> 8 15,20 26,43 45</td></tr><tr><td style="width:86px;">输出</td><td style="width:412px;">Life is painting a picture, not doing &#39;a  sum&#39;.<br /> [8, 15][19, 25][42, 44]</td></tr><tr><td style="width:86px;">说明</td><td style="width:412px;"> <p>a和picture中间多余的空格进行删除</p> </td></tr></tbody></table> 
<table border="1" cellpadding="1" cellspacing="1" style="width:500px;"><tbody><tr><td style="width:86px;">输入</td><td style="width:412px;">Life is painting a picture, not doing &#39;a  sum&#39;.<br /> 8 15,19 25,42 44</td></tr><tr><td style="width:86px;">输出</td><td style="width:412px;"> <p>Life is painting a picture, not doing &#39;a  sum&#39;.<br /> [8, 15][19, 25][42, 44]</p> </td></tr><tr><td style="width:86px;">说明</td><td style="width:412px;">a和sum之间有多余的空格&#xff0c;但是因为有成对单引号&#xff0c;不去除多余空格</td></tr></tbody></table> 
<h4 id="%E9%A2%98%E7%9B%AE%E8%A7%A3%E6%9E%90">题目解析</h4> 
<p>用例1图示</p> 
<p><img alt="" height="237" src="https://img-blog.csdnimg.cn/8cde5d2e2c714ca082040d5062780baf.png" width="1200" /></p> 
<p></p> 
<p>用例2图示</p> 
<p><img alt="" height="235" src="https://img-blog.csdnimg.cn/d345d181cca1433aa7a34c2ea04a99dc.png" width="1200" /></p> 
<p></p> 
<p>我的解题思路如下&#xff1a;</p> 
<p>定义一个数组needDel&#xff0c;记录需要被删除的空格的位置&#xff0c;定义一个变量quotaStart&#xff0c;记录是否已有未闭合的单引号&#xff0c;默认为false&#xff0c;即没有。</p> 
<p></p> 
<p>遍历输入字符串的每一个字符&#xff0c;</p> 
<p>首先看被遍历的字符c是不是&#34; &#34;空格</p> 
<ul><li>如果不是&#xff0c;则继续后面逻辑</li><li>如果是&#xff0c;则看当前遍历字符的前一个字符是不是也是“ ”&#xff0c;如果不是则继续后面逻辑&#xff0c;如果是&#xff0c;则看quotaStart是否为false&#xff0c;若不是&#xff0c;则继续后面逻辑&#xff0c;若是&#xff0c;则说明空格c就是需要删除的空格&#xff0c;我们将其索引位置记录到needDel中</li></ul> 
<p>然后看遍历的字符c是不是单引号&#xff0c;若是&#xff0c;则将quotaStart取反&#xff08;表示单引号开闭&#xff09;</p> 
<p></p> 
<p>当扫描完后&#xff0c;我们就可以做两件事&#xff1a;</p> 
<p>1、将输入字符串转为数组&#xff0c;根据needDel中记录的索引&#xff0c;来删除对应空格&#xff08;即替换对应数组元素为“”空串&#xff09;&#xff0c;然后将数组join后打印</p> 
<p>2、双重for&#xff0c;外层遍历needDel获得每一个要删除的空格的索引&#xff0c;内存遍历题目第一行输入的多组开始、结束位置arr&#xff0c;如果要删除的空格处于开始位置之前&#xff0c;则对应开始&#xff0c;结束位置都要减去1。</p> 
<p>我们需要注意的是&#xff1a;我们不能基于原始的arr处理&#xff0c;应该对arr进行深拷贝后&#xff0c;对拷贝数组进行处理&#xff0c;因为如果基于原始arr进行处理&#xff0c;则会造成needDel中要删除的索引&#xff0c;和arr中记录的索引不同步。</p> 
<p>比如 needDel &#61; [18,19]&#xff0c;arr &#61; [ [8,15], [20,26], [43,45] ]</p> 
<p>如果我们直接在arr上进行操作&#xff0c;则</p> 
<p>首先needDel遍历出18&#xff0c;然后对比每一个arr范围的开始位置&#xff0c;发现[20,26], [43,45]在18后面&#xff0c;因此当18位置的空格删除后&#xff0c;这两个范围都要前移&#xff0c;因此arr变为了[[8,15], [19,25], [42,44]]。</p> 
<p>之后needDel遍历出19&#xff0c;然后对比每一个arr范围的开始位置&#xff0c;发现和[19,25]产生了冲突&#xff0c;因为19坐标位置既是要删除的空格&#xff0c;又是一个关键词的起始位置&#xff0c;造成这种冲突的原因是此时needDel 19 和 arr范围[19,25] 已经不同步了。</p> 
<p>因此我们要对&#xff0c;arr进行深拷贝后&#xff08;数组元素是数组&#xff0c;需要深拷贝&#xff0c;可以使用最简单的JSON方法实现深拷贝&#xff09;&#xff0c;然后needDel和原始arr进行对比操作&#xff0c;具体范围移动操作在arr的拷贝对象上处理。</p> 
<p></p> 
<p>但是本题的文本字符长度length取值范围&#xff1a;[0, 100000];</p> 
<p>这个有点大啊&#xff0c;会不会爆内存呢&#xff1f;有点悬。</p> 
<p></p> 
<h4 id="%E7%AE%97%E6%B3%95%E6%BA%90%E7%A0%81">JavaScript算法源码</h4> 
<p>克隆版&#xff08;85%通过率&#xff09;</p> 
<pre><code class="language-javascript">/* JavaScript Node ACM模式 控制台输入获取 */
const readline &#61; require(&#34;readline&#34;);

const rl &#61; readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines &#61; [];
rl.on(&#34;line&#34;, (line) &#61;&gt; {
  lines.push(line);

  if (lines.length &#61;&#61;&#61; 2) {
    const str &#61; lines[0];
    const arr &#61; lines[1].split(&#34;,&#34;).map((pos) &#61;&gt; pos.split(&#34; &#34;).map(Number));
    getResult(arr, str);
    lines.length &#61; 0;
  }
});

function getResult(arr, str) {
  let quotaStart &#61; false;
  const needDel &#61; [];
  for (let i &#61; 0; i &lt; str.length; i&#43;&#43;) {
    if (str[i] &#61;&#61;&#61; &#34; &#34; &amp;&amp; str[i - 1] &#61;&#61;&#61; &#34; &#34; &amp;&amp; !quotaStart) {
      needDel.push(i);
    }

    if (str[i] &#61;&#61;&#61; &#34;&#39;&#34;) {
      quotaStart &#61; !quotaStart;
    }
  }

  const strArr &#61; [...str];
  const ans &#61; JSON.parse(JSON.stringify(arr)); // 深拷贝
  for (let del of needDel) {
    strArr[del] &#61; &#34;&#34;;
    for (let i &#61; 0; i &lt; arr.length; i&#43;&#43;) {
      const [start] &#61; arr[i];
      if (del &lt; start) {
        ans[i][0]--;
        ans[i][1]--;
      }
    }
  }

  console.log(strArr.join(&#34;&#34;));
  console.log(ans.map((ran) &#61;&gt; &#96;[${ran.join(&#34;, &#34;)}]&#96;).join(&#34;&#34;));
}
</code></pre> 
<p>倒序版</p> 
<pre><code class="language-javascript">/* JavaScript Node ACM模式 控制台输入获取 */
const readline &#61; require(&#34;readline&#34;);

const rl &#61; readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines &#61; [];
rl.on(&#34;line&#34;, (line) &#61;&gt; {
  lines.push(line);

  if (lines.length &#61;&#61;&#61; 2) {
    const str &#61; lines[0];
    const arr &#61; lines[1].split(&#34;,&#34;).map((pos) &#61;&gt; pos.split(&#34; &#34;).map(Number));
    getResult(arr, str);
    lines.length &#61; 0;
  }
});

function getResult(arr, str) {
  let quotaStart &#61; false;
  const needDel &#61; [];
  for (let i &#61; 0; i &lt; str.length; i&#43;&#43;) {
    if (str[i] &#61;&#61;&#61; &#34; &#34; &amp;&amp; str[i - 1] &#61;&#61;&#61; &#34; &#34; &amp;&amp; !quotaStart) {
      needDel.push(i);
    }

    if (str[i] &#61;&#61;&#61; &#34;&#39;&#34;) {
      quotaStart &#61; !quotaStart;
    }
  }

  const strArr &#61; [...str];
  for (let i &#61; needDel.length - 1; i &gt;&#61; 0; i--) {
    const del &#61; needDel[i];
    strArr[del] &#61; &#34;&#34;;
    for (let i &#61; 0; i &lt; arr.length; i&#43;&#43;) {
      const start &#61; arr[i][0];
      if (del &lt; start) {
        arr[i][0]--;
        arr[i][1]--;
      }
    }
  }

  console.log(strArr.join(&#34;&#34;));
  console.log(arr.map((ran) &#61;&gt; &#96;[${ran.join(&#34;, &#34;)}]&#96;).join(&#34;&#34;));
}
</code></pre> 
<p></p> 
<p></p> 
<h4>Java算法源码</h4> 
<p>克隆版&#xff08;85%通过率&#xff09;</p> 
<pre><code class="language-java">import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc &#61; new Scanner(System.in);

        String str &#61; sc.nextLine();

        Integer[][] ranges &#61;
                Arrays.stream(sc.nextLine().split(&#34;,&#34;))
                        .map(s -&gt; Arrays.stream(s.split(&#34; &#34;))
                                .map(Integer::parseInt)
                                .toArray(Integer[]::new))
                        .toArray(Integer[][]::new);

        getResult(str, ranges);
    }

    public static void getResult(String str, Integer[][] ranges) {
        boolean quotaStart &#61; false;
        ArrayList&lt;Integer&gt; needDel &#61; new ArrayList&lt;&gt;();

        for (int i &#61; 0; i &lt; str.length(); i&#43;&#43;) {
            if (i &gt; 0 &amp;&amp; &#39; &#39; &#61;&#61; str.charAt(i) &amp;&amp; &#39; &#39; &#61;&#61; str.charAt(i - 1) &amp;&amp; !quotaStart) {
                needDel.add(i);
            }

            if (&#39;\&#39;&#39; &#61;&#61; str.charAt(i)) {
                quotaStart &#61; !quotaStart;
            }
        }

        char[] cArr &#61; str.toCharArray();
        Integer[][] ans &#61; Arrays.stream(ranges).map(Integer[]::clone).toArray(Integer[][]::new);

        for (Integer del : needDel) {
            cArr[del] &#61; &#39;\u0000&#39;;
            for (int i &#61; 0; i &lt; ranges.length; i&#43;&#43;) {
                int start &#61; ranges[i][0];
                if (del &lt; start) {
                    ans[i][0]--;
                    ans[i][1]--;
                }
            }
        }

        System.out.println(new String(cArr).replace(&#34;\u0000&#34;, &#34;&#34;));

        StringBuilder sb &#61; new StringBuilder();
        for (Integer[] an : ans) {
            sb.append(Arrays.toString(an));
        }
        System.out.println(sb);


    }
}</code></pre> 
<p>倒序版</p> 
<pre><code class="language-java">import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc &#61; new Scanner(System.in);

    String str &#61; sc.nextLine();

    Integer[][] ranges &#61;
        Arrays.stream(sc.nextLine().split(&#34;,&#34;))
            .map(s -&gt; Arrays.stream(s.split(&#34; &#34;)).map(Integer::parseInt).toArray(Integer[]::new))
            .toArray(Integer[][]::new);

    getResult(str, ranges);
  }

  public static void getResult(String str, Integer[][] ranges) {
    boolean quotaStart &#61; false;
    ArrayList&lt;Integer&gt; needDel &#61; new ArrayList&lt;&gt;();

    String[] sArr &#61; str.split(&#34;&#34;);

    for (int i &#61; 0; i &lt; sArr.length; i&#43;&#43;) {
      if (i &gt; 0 &amp;&amp; &#34; &#34;.equals(sArr[i]) &amp;&amp; &#34; &#34;.equals(sArr[i - 1]) &amp;&amp; !quotaStart) {
        needDel.add(i);
      }

      if (&#34;&#39;&#34;.equals(sArr[i])) {
        quotaStart &#61; !quotaStart;
      }
    }

    for (int j &#61; needDel.size() - 1; j &gt;&#61; 0; j--) {
      int del &#61; needDel.get(j);
      sArr[del] &#61; &#34;&#34;;
      for (int i &#61; 0; i &lt; ranges.length; i&#43;&#43;) {
        int start &#61; ranges[i][0];
        if (del &lt; start) {
          ranges[i][0]--;
          ranges[i][1]--;
        }
      }
    }

    StringBuilder tmp &#61; new StringBuilder();
    for (String s : sArr) {
      tmp.append(s);
    }
    System.out.println(tmp);

    StringBuilder sb &#61; new StringBuilder();
    for (Integer[] an : ranges) {
      sb.append(Arrays.toString(an));
    }
    System.out.println(sb);
  }
}
</code></pre> 
<p></p> 
<h4>Python算法源码</h4> 
<p>克隆版</p> 
<pre><code class="language-python">import copy

# 输入获取
s &#61; input()
arr &#61; list(map(lambda x: list(map(int, x.split())), input().split(&#34;,&#34;)))


# 算法入口
def getResult(arr, s):
    quotaStart &#61; False
    needDel &#61; []

    for i in range(len(s)):
        if s[i] &#61;&#61; &#34; &#34; and s[i - 1] &#61;&#61; &#34; &#34; and i &gt; 0 and not quotaStart:
            needDel.append(i)

        if s[i] &#61;&#61; &#34;\&#39;&#34;:
            quotaStart &#61; not quotaStart

    sArr &#61; list(s)
    ans &#61; copy.deepcopy(arr)

    for d in needDel:
        sArr[d] &#61; &#34;&#34;
        for i in range(len(arr)):
            start &#61; arr[i][0]
            if d &lt; start:
                ans[i][0] -&#61; 1
                ans[i][1] -&#61; 1

    print(&#34;&#34;.join(sArr))
    print(&#34;&#34;.join(list(map(lambda x: str(x), ans))))


# 算法调用
getResult(arr, s)
</code></pre> 
<p></p> 
<p>倒序版</p> 
<pre><code class="language-python"># 输入获取
s &#61; input()
arr &#61; list(map(lambda x: list(map(int, x.split())), input().split(&#34;,&#34;)))


# 算法入口
def getResult(arr, s):
    quotaStart &#61; False
    needDel &#61; []

    for i in range(len(s)):
        if s[i] &#61;&#61; &#34; &#34; and s[i - 1] &#61;&#61; &#34; &#34; and i &gt; 0 and not quotaStart:
            needDel.append(i)

        if s[i] &#61;&#61; &#34;&#39;&#34;:
            quotaStart &#61; not quotaStart

    sArr &#61; list(s)

    needDel.reverse()
    for d in needDel:
        sArr[d] &#61; &#34;&#34;
        for i in range(len(arr)):
            start &#61; arr[i][0]
            if d &lt; start:
                arr[i][0] -&#61; 1
                arr[i][1] -&#61; 1

    print(&#34;&#34;.join(sArr))
    print(&#34;&#34;.join(list(map(lambda x: str(x), arr))))


# 算法调用
getResult(arr, s)
</code></pre> 
<p></p>
                </div>
        </div>
        <div id="treeSkill"></div>
        <div id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"></div>
    <script>
  $(function() {
    setTimeout(function () {
      var mathcodeList = document.querySelectorAll('.htmledit_views img.mathcode');
      if (mathcodeList.length > 0) {
        for (let i = 0; i < mathcodeList.length; i++) {
          if (mathcodeList[i].naturalWidth === 0 || mathcodeList[i].naturalHeight === 0) {
            var alt = mathcodeList[i].alt;
            alt = '\\(' + alt + '\\)';
            var curSpan = $('<span class="img-codecogs"></span>');
            curSpan.text(alt);
            $(mathcodeList[i]).before(curSpan);
            $(mathcodeList[i]).remove();
          }
        }
        MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
      }
    }, 1000)
  });
</script>
</div></html>